home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 11
/
CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso
/
www
/
http
/
www.amigasupport.com
/
software
/
arc
/
fpvoc.lha
/
Source
/
dispatch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-22
|
11KB
|
422 lines
/******************************************************************************
*
* VOC Datatype, based on the sourcecode found in OS3.1 Native Developer Kit
*
* Written by Christian Buchner
*
******************************************************************************
* dispatch.c
*/
#include "classbase.h"
/*****************************************************************************/
#define DEBUG 0
#if DEBUG
#define DB(x) x
#include <stdarg.h>
void __stdargs Error(struct ClassBase *cb,UBYTE *Msg,...)
{
va_list Arg;
struct EasyStruct Req={sizeof(struct EasyStruct),0,"VOC debug message",0,"Okay"};
va_start(Arg,Msg);
Req.es_TextFormat=Msg;
EasyRequestArgs(NULL,&Req,0,Arg);
va_end(Arg);
}
#else
#define DB(x)
#endif
/*****************************************************************************/
Class *initClass (struct ClassBase * cb)
{
Class *cl;
if (cl = MakeClass (VOCDTCLASS, SOUNDDTCLASS, NULL, NULL, 0L))
{
cl->cl_Dispatcher.h_Entry = (ULONG (*)())Dispatch;
cl->cl_UserData = (ULONG) cb;
AddClass (cl);
}
return (cl);
}
/*****************************************************************************/
ULONG ASM Dispatch (REG (a0) Class * cl, REG (a2) Object * o, REG (a1) Msg msg)
{
struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
ULONG retval = 0L;
switch (msg->MethodID)
{
case OM_NEW:
if (retval = DoSuperMethodA (cl, o, msg))
{
if (!(ConvertObjectData (cb, cl, (Object *) retval, ((struct opSet *) msg)->ops_AttrList)))
{
CoerceMethod (cl, (Object *) retval, OM_DISPOSE);
retval = NULL;
}
}
break;
/* Let the superclass handle everything else */
default:
retval = (ULONG) DoSuperMethodA (cl, o, msg);
break;
}
return (retval);
}
/*****************************************************************************/
#define GETLONG(a) ( (*(a)) + (*(a+1)<<8) + (*(a+2)<<16) + (*(a+3)<<24) )
#define GETTRIPLE(a) ( (*(a)) + (*(a+1)<<8) + (*(a+2)<<16) )
#define GETWORD(a) ( (*(a)) + (*(a+1)<<8) )
#define SWAPW(a) (WORD)(((UWORD)a>>8)+((((UWORD)a&0xff)<<8)))
#define SWAPU(a) (UWORD)(((UWORD)a>>8)+((((UWORD)a&0xff)<<8)))
#define SWAPL(a) (LONG)(((ULONG)a>>24)+(((ULONG)a&0xff0000)>>8)+(((ULONG)a&0xff00)<<8)+(((ULONG)a&0xff)<<24))
/*****************************************************************************/
#define ID_Terminator 0
#define ID_Sounddata 1
#define ID_Soundcontinue 2
#define ID_Silence 3
#define ID_Marker 4
#define ID_ASCII 5
#define ID_Repeat 6
#define ID_Endrepeat 7
#define ID_Extended 8
/*****************************************************************************/
struct SoundInfo
{
UBYTE soi_SampleRate;
UBYTE soi_Compression;
UBYTE soi_Data;
};
#define VOCFORMAT_8BIT 0
#define VOCFORMAT_4BIT 1
#define VOCFORMAT_26BIT 2
#define VOCFORMAT_2BIT 3
#define VOCFORMAT_MDAC 4
struct SilenceInfo
{
UWORD sil_Length;
UBYTE sil_SampleRate;
};
struct ExtendedInfo
{
UWORD exi_TimeConstant;
UBYTE exi_Compression;
UBYTE exi_Mode;
};
#define MODE_MONO 0
#define MODE_STEREO 1
/*****************************************************************************/
/*****************************************************************************/
BOOL ConvertObjectData (struct ClassBase * cb, Class * cl, Object * o, struct TagItem * attrs)
{
LONG ErrorCode=0;
struct FileInfoBlock *fib;
struct VoiceHeader *vhdr;
STRPTR title;
LONG size;
ULONG len;
BPTR fh;
STRPTR buffer, ptr;
UBYTE pass;
UBYTE ID;
ULONG Memory;
ULONG SampleLength;
ULONG SampleFreq;
ULONG Frequency=10000;
UBYTE Mode=MODE_MONO;
UBYTE *Sample;
UBYTE *Dest=0;
ULONG DestLength;
title = (STRPTR) GetTagData (DTA_Name, NULL, attrs);
getdtattrs (cb, o,
SDTA_VoiceHeader, &vhdr,
DTA_Handle, &fh,
TAG_DONE);
if (fh && vhdr)
{
/* Allocate a temporary file info block */
if (!(fib = (struct FileInfoBlock *) AllocMem (sizeof (struct FileInfoBlock), NULL)))
{
ErrorCode=ERROR_NO_FREE_STORE;
DB(Error(cb,"not enough memory"));
}
else
{
/* Get the size of the file */
if (ExamineFH (fh, fib))
{
size = fib->fib_Size;
}
else
{
Seek (fh, 0, OFFSET_END);
size = Seek (fh, 0, OFFSET_BEGINNING);
}
/* Free the temporary file info block */
FreeMem (fib, sizeof (struct FileInfoBlock));
/* Buffered IO block */
if (!(buffer = AllocVec (size, NULL)))
{
ErrorCode=ERROR_NO_FREE_STORE;
DB(Error(cb,"not enough memory"));
}
else
{
/* Read the whole file into the buffer */
if (Read (fh, buffer, size) != size)
{
DB(Error(cb,"couldn't read %ld bytes : error=%ld", size, IoErr ()));
}
else
{
if (strncmp(buffer, "Creative Voice File\32",20))
{
ErrorCode=ERROR_OBJECT_WRONG_TYPE;
DB(Error(cb,"unknown format"));
}
else
{
/* 3-Pass loop over whole VOC Sample */
/* 1. Pass: find out highest sample rate */
/* 2. Pass: determine length of whole sample */
/* 3. Pass: synthesize 8-Bit sample by using */
/* highest samplerate */
SampleFreq=0;
SampleLength=0;
for (pass=1;(!ErrorCode) && pass<=3;pass++)
{
/* get offset of the first data block to ptr */
ptr=buffer+GETWORD(buffer+20);
/* loop through cunks until end of buffer reached */
while((!ErrorCode) && (ID=*ptr) && (ptr<buffer+size))
{
len=GETTRIPLE(ptr+1);
ptr+=4;
/* Handle the different chunks */
switch(ID)
{
case ID_Sounddata:
{
struct SoundInfo *soi=(struct SoundInfo*)ptr;
/* MUST be uncompressed 8 bit PCM data */
if (soi->soi_Compression == VOCFORMAT_8BIT)
{
Mode=MODE_MONO; /* Force MONO mode */
/* don't know whether this is correct */
/* missing some documentation! */
Frequency=1000000/(256-soi->soi_SampleRate);
DestLength=ScaleLength(len-sizeof(struct SoundInfo),Frequency,SampleFreq);
/* pass 1: Determine highest freq */
if (pass==1) if (Frequency>SampleFreq) SampleFreq=Frequency;
/* pass 2: calculate sample size */
if (pass==2) SampleLength+=DestLength;
/* pass 3: convert sample data */
if (pass==3) Convert(ptr+sizeof(struct SoundInfo), &Dest, DestLength, Frequency, SampleFreq, Mode);
}
else
{
ErrorCode=DTERROR_UNKNOWN_COMPRESSION;
DB(Error(cb,"unknown compression"));
}
}
break;
case ID_Soundcontinue:
{
/* Frequency and Mode may have been */
/* initialized by ID_Extended */
DestLength=ScaleLength(len,Frequency,SampleFreq);
if (Mode==MODE_STEREO) DestLength/=2;
/* pass 1: Determine highest freq */
if (pass==1) if (Frequency>SampleFreq) SampleFreq=Frequency;
/* pass 2: calculate sample size */
if (pass==2) SampleLength+=DestLength;
/* pass 3: convert sample data */
if (pass==3) Convert(ptr, &Dest, DestLength, Frequency, SampleFreq, Mode);
}
break;
case ID_Silence:
{
struct SilenceInfo *sil=(struct SilenceInfo*)ptr;
Frequency=1000000/(256-sil->sil_SampleRate);
DestLength=ScaleLength(((ULONG)(SWAPW(sil->sil_Length)+1)),Frequency,SampleFreq);
/* pass 2: calculate sample size */
if (pass==2) SampleLength+=DestLength;
/* pass 3: just skip (leave silent) */
if (pass==3) Dest+=DestLength;
}
break;
case ID_Extended:
{
struct ExtendedInfo *exi=(struct ExtendedInfo*)ptr;
if (exi->exi_Compression != VOCFORMAT_8BIT)
{
ErrorCode=DTERROR_UNKNOWN_COMPRESSION;
DB(Error(cb,"unknown compression"));
}
else
{
if (exi->exi_Mode != MODE_MONO && exi->exi_Mode != MODE_STEREO)
{
ErrorCode=ERROR_OBJECT_WRONG_TYPE;
DB(Error(cb,"unknown type"));
}
else
{
Mode=exi->exi_Mode;
Frequency=256000000/(65536-SWAPW(exi->exi_TimeConstant));
if (Mode==MODE_STEREO) Frequency/=2;
}
}
}
default:
{
DB(Error(cb,"unknown chunk: %ld, Len: %ld",(long)ID,len));
}
break;
}
ptr=ptr+len;
}
if (pass==2)
{
/* sound.datatype V40 can replay */
/* directly from Fast RAM */
Memory = (SuperClassBase->lib_Version>39) ?
MEMF_ANY : MEMF_CHIP;
if (Sample=AllocVec(SampleLength, Memory | MEMF_CLEAR))
{
/* Fill in the voice header */
memset(vhdr,0,sizeof(struct VoiceHeader));
vhdr->vh_OneShotHiSamples = SampleLength;
vhdr->vh_SamplesPerSec = SampleFreq;
vhdr->vh_Octaves = 1;
vhdr->vh_Compression = CMP_NONE;
vhdr->vh_Volume = 64;
/* Tell the super-class about the attributes */
setdtattrs (cb, o,
DTA_ObjName, title,
SDTA_Sample, Sample,
SDTA_SampleLength, SampleLength,
SDTA_Period, (ULONG)(SysBase->ex_EClockFrequency*5)/SampleFreq,
SDTA_Volume, 64,
SDTA_Cycles, 1,
TAG_DONE);
Dest=Sample;
}
else
{
ErrorCode=ERROR_NO_FREE_STORE;
DB(Error(cb,"not enough memory"));
}
}
}
}
}
/* Free the buffer */
FreeVec(buffer);
}
}
}
if (ErrorCode)
{
SetIoErr(ErrorCode);
return(FALSE);
}
return(TRUE);
}
/*****************************************************************************/
/* Convert the unsigned sample data to 8 bit signed PCM format */
/* and do a time stretching if necessary */
/* Destination pointer will be incremented */
/* This one calls assembly routines for speed reasons */
void Convert(UBYTE *Source, UBYTE **Dest, ULONG DestLength, ULONG SourceFreq, ULONG DestFreq, UBYTE Mode)
{
if (Mode==MODE_MONO)
{
ConvertMono8(Source, *Dest, DestLength, SourceFreq, DestFreq);
}
if (Mode==MODE_STEREO)
{
ConvertStereo8(Source, *Dest, DestLength, SourceFreq, DestFreq);
}
*Dest+=DestLength;
}
/*****************************************************************************/
ULONG setdtattrs (struct ClassBase * cb, Object * o, ULONG data,...)
{
return (SetDTAttrsA (o, NULL, NULL, (struct TagItem *) & data));
}
/*****************************************************************************/
ULONG getdtattrs (struct ClassBase * cb, Object * o, ULONG data,...)
{
return (GetDTAttrsA (o, (struct TagItem *) & data));
}